import { HttpContext } from '@angular/common/http';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit, inject } from '@angular/core';
import { AbstractControl, FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import { StartupService } from '@core';
import { ReuseTabService } from '@delon/abc/reuse-tab';
import { ALLOW_ANONYMOUS, DA_SERVICE_TOKEN, JWTTokenModel } from '@delon/auth';
import { I18nPipe, _HttpClient } from '@delon/theme';
import { environment } from '@env/environment';
import { NzAlertModule } from 'ng-zorro-antd/alert';
import { NzButtonModule } from 'ng-zorro-antd/button';
import { NzCheckboxModule } from 'ng-zorro-antd/checkbox';
import { NzSafeAny } from 'ng-zorro-antd/core/types';
import { NzFormModule } from 'ng-zorro-antd/form';
import { NzIconModule } from 'ng-zorro-antd/icon';
import { NzImageModule } from 'ng-zorro-antd/image';
import { NzInputModule } from 'ng-zorro-antd/input';
import { NzMessageService } from 'ng-zorro-antd/message';
import { NzTabChangeEvent, NzTabsModule } from 'ng-zorro-antd/tabs';
import { NzToolTipModule } from 'ng-zorro-antd/tooltip';
import { finalize } from 'rxjs';
import { Api } from 'src/app/shared/api/api';
import { ResponseCode } from 'src/app/shared/response.code';
import { encryptByRSA } from 'src/app/shared/utils/crypto';

@Component({
  selector: 'passport-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.less'],
  providers: [],
  changeDetection: ChangeDetectionStrategy.Default,
  imports: [
    RouterLink,
    ReactiveFormsModule,
    I18nPipe,
    NzCheckboxModule,
    NzTabsModule,
    NzAlertModule,
    NzFormModule,
    NzInputModule,
    NzButtonModule,
    NzToolTipModule,
    NzIconModule,
    NzImageModule
  ]
})
export class UserLoginComponent implements OnInit, OnDestroy {
  private readonly router = inject(Router);
  private readonly msg = inject(NzMessageService);
  private readonly reuseTabService = inject(ReuseTabService, { optional: true });
  private readonly tokenService = inject(DA_SERVICE_TOKEN);
  private readonly startupSrv = inject(StartupService);
  private readonly http = inject(_HttpClient);
  private readonly cdr = inject(ChangeDetectorRef);
  wechatQrUrl: SafeResourceUrl = '';
  publicKey = '';
  passwordCaptcha: NzSafeAny = {};
  phoneCaptcha: NzSafeAny = {};
  target = '';
  form = inject(FormBuilder).nonNullable.group({
    userName: ['', [Validators.required, Validators.minLength(4)]],
    password: ['', [Validators.required]],
    passwordCode: ['', [Validators.required]],
    mobile: ['', [Validators.required, Validators.pattern(/^1\d{10}$/)]],
    captcha: ['', [Validators.required]],
    phoneCode: ['', [Validators.required]],
    remember: [true]
  });

  get userName(): AbstractControl {
    return this.form.get('userName')!;
  }
  get password(): AbstractControl {
    return this.form.get('password')!;
  }
  get imageCode(): AbstractControl {
    return this.form.get('passwordCode')!;
  }
  get mobile(): AbstractControl {
    return this.form.get('mobile')!;
  }
  get captcha(): AbstractControl {
    return this.form.get('captcha')!;
  }

  error = '';
  type = 0;
  loading = false;

  count = 0;
  interval$: NzSafeAny;
  appid = environment['wechatInfo'].appId; //'wx9218797a4cf670c6';
  redirectUrl = encodeURIComponent(environment['wechatInfo'].redirectUri); // 'https%3A%2F%2Fwww.yigongyun.cloud%2F%23%2Fpassport%2Fcallback&state=123456';

  private readonly route = inject(ActivatedRoute);
  private readonly sanitizer = inject(DomSanitizer);

  constructor() {
    this.wechatQrUrl = this.sanitizer.bypassSecurityTrustResourceUrl(
      `https://open.weixin.qq.com/connect/qrconnect?appid=${this.appid}&scope=snsapi_login,snsapi_userinfo&redirect_uri=${this.redirectUrl}&state=123456&login_type=jssdk&self_redirect=false&styletype=&sizetype=&bgcolor=&rst=&style=black`
    );
    this.route.queryParams.subscribe(res => {
      this.type = res['type'] || 0;
      this.target = res['target'] || '';
    });
  }

  ngOnInit(): void {
    this.getPublicKey();
    this.refreshCaptcha();
  }

  switch({ index }: NzTabChangeEvent): void {
    this.type = index!;
    this.refreshCaptcha();
  }

  getPasswordCaptch() {
    this.http
      .get(Api.PasswordCaptchaApi, null, {
        context: new HttpContext().set(ALLOW_ANONYMOUS, true)
      })
      .subscribe(res => {
        if (res.code == ResponseCode.SUCCESS) {
          this.passwordCaptcha = res.data;
        }
      });
  }

  getPhoneCaptcha() {
    this.http
      .get(Api.PhoneCaptchaApi, null, {
        context: new HttpContext().set(ALLOW_ANONYMOUS, true)
      })
      .subscribe(res => {
        if (res.code == ResponseCode.SUCCESS) {
          this.phoneCaptcha = res.data;
        }
      });
  }

  getCaptcha(): void {
    const mobile = this.form.controls.mobile;
    const phoneCode = this.form.controls.phoneCode;
    if (mobile.invalid) {
      mobile.markAsDirty({ onlySelf: true });
      mobile.updateValueAndValidity({ onlySelf: true });
      return;
    }
    if (phoneCode.invalid) {
      phoneCode.markAsDirty({ onlySelf: true });
      phoneCode.updateValueAndValidity({ onlySelf: true });
      return;
    }
    this.error = '';
    this.http
      .get(`${Api.MessageCaptchaApi}?mobile=${mobile.value}&captcha=${phoneCode.value}&captchaId=${this.phoneCaptcha?.captchaId}`, null, {
        context: new HttpContext().set(ALLOW_ANONYMOUS, true)
      })
      .subscribe({
        next: res => {
          if (res.code == ResponseCode.SUCCESS) {
            this.count = 59;
            this.interval$ = setInterval(() => {
              this.count -= 1;
              if (this.count <= 0) {
                clearInterval(this.interval$);
              }
            }, 1000);
          } else {
            this.error = res.message;
          }
        },
        error: _err => {
          this.msg.error(_err);
        }
      });
  }

  getPublicKey() {
    this.http
      .get(Api.PublicKeyApi, null, {
        context: new HttpContext().set(ALLOW_ANONYMOUS, true)
      })
      .subscribe((res: NzSafeAny) => {
        if (res && res.code === ResponseCode.SUCCESS) {
          if (res.data) this.publicKey = res.data;
        }
      });
  }

  refreshCaptcha() {
    if (this.type == 0) this.getPasswordCaptch();
    else if (this.type == 1) {
      this.getPhoneCaptcha();
    }
    if (this.target) {
      this.goTarget();
    }
  }

  submit(): void {
    this.error = '';
    let loginUrl = '';
    if (this.type === 0) {
      const { userName, password, passwordCode } = this.form.controls;
      userName.markAsDirty();
      userName.updateValueAndValidity();
      password.markAsDirty();
      password.updateValueAndValidity();
      passwordCode.markAsDirty();
      passwordCode.updateValueAndValidity();
      if (userName.invalid || password.invalid || passwordCode.invalid) {
        return;
      }
      loginUrl = Api.PasswordLoginApi;
    } else if (this.type == 1) {
      const { mobile, captcha, phoneCode } = this.form.controls;
      mobile.markAsDirty();
      mobile.updateValueAndValidity();
      captcha.markAsDirty();
      captcha.updateValueAndValidity();
      phoneCode.markAsDirty();
      phoneCode.updateValueAndValidity();
      if (mobile.invalid || captcha.invalid || phoneCode.invalid) {
        return;
      }
      loginUrl = Api.PhoneLoginApi;
    }

    this.error = '';
    this.loading = true;

    const encryptPassword = this.type == 0 ? encryptByRSA(this.publicKey, this.password.value) : '';
    const encryptUsername = this.type == 0 ? encryptByRSA(this.publicKey, this.userName.value) : '';
    const encryptImageCode = this.type == 0 ? encryptByRSA(this.publicKey, this.imageCode.value) : '';
    const encryptCaptchaId = this.type == 0 ? encryptByRSA(this.publicKey, this.passwordCaptcha?.captchaId || '') : '';

    const encryptCaptcha = this.type == 1 ? encryptByRSA(this.publicKey, this.captcha.value) : '';
    const encryptMobile = this.type == 1 ? encryptByRSA(this.publicKey, this.mobile.value) : '';

    let data = new FormData();
    if (this.type == 0) {
      data.append('username', encryptUsername as string);
      data.append('password', encryptPassword as string);
      data.append('captcha', encryptImageCode as string);
      data.append('captchaId', encryptCaptchaId as string);
    } else if (this.type == 1) {
      data.append('code', encryptCaptcha as string);
      data.append('mobile', encryptMobile as string);
    }
    this.http
      .post(
        loginUrl,
        data,
        {},
        {
          context: new HttpContext().set(ALLOW_ANONYMOUS, true)
        }
      )
      .pipe(
        finalize(() => {
          this.loading = false;
          this.cdr.detectChanges();
        })
      )
      .subscribe({
        next: (res: NzSafeAny) => {
          if (res.code !== ResponseCode.SUCCESS) {
            this.error = res.message;
            this.refreshCaptcha();
            return;
          }
          // 清空路由复用信息
          this.reuseTabService?.clear();
          // 设置用户Token信息
          const user = { token: res.data };
          this.tokenService.set(user);
          if (this.target) {
            this.goTarget();
          } else {
            // 重新获取 StartupService 内容，我们始终认为应用信息一般都会受当前用户授权范围而影响
            this.startupSrv.load().subscribe(() => {
              let url = this.tokenService.referrer!.url || '/';
              if (url.includes('/passport')) {
                url = '/';
              }
              this.router.navigateByUrl(url);
            });
          }
        },
        error: err => {
          this.msg.error(err);
          this.refreshCaptcha();
        }
      });
  }

  goTarget() {
    let jwtTkoen = this.tokenService.get(JWTTokenModel);
    if (jwtTkoen && jwtTkoen?.token) {
      window.location.href = `${this.target}&token=${jwtTkoen.token}`;
    }
  }

  ngOnDestroy(): void {
    if (this.interval$) {
      clearInterval(this.interval$);
    }
  }
}
